﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;

namespace HslCommunication.Algorithms.Fourier
{
	/// <summary>
	/// 离散傅氏变换的快速算法，处理的信号，适合单周期信号数为2的N次方个，支持变换及逆变换
	/// </summary>
	// Token: 0x020001A8 RID: 424
	public class FFTHelper
	{
		/// <summary>
		///
		/// </summary>
		/// <param name="xreal"></param>
		/// <param name="ximag"></param>
		/// <param name="n"></param>
		// Token: 0x06002157 RID: 8535 RVA: 0x000A1ED8 File Offset: 0x000A00D8
		private static void bitrp(double[] xreal, double[] ximag, int n)
		{
			int i = 1;
			int num = 0;
			while (i < n)
			{
				num++;
				i *= 2;
			}
			for (i = 0; i < n; i++)
			{
				int num2 = i;
				int num3 = 0;
				for (int j = 0; j < num; j++)
				{
					num3 = num3 * 2 + num2 % 2;
					num2 /= 2;
				}
				bool flag = num3 > i;
				if (flag)
				{
					double num4 = xreal[i];
					xreal[i] = xreal[num3];
					xreal[num3] = num4;
					num4 = ximag[i];
					ximag[i] = ximag[num3];
					ximag[num3] = num4;
				}
			}
		}

		/// <summary>
		/// 快速傅立叶变换
		/// </summary>
		/// <param name="xreal">实数部分</param>
		/// <returns>变换后的数组值</returns>
		// Token: 0x06002158 RID: 8536 RVA: 0x000A1F68 File Offset: 0x000A0168
		public static double[] FFT(double[] xreal)
		{
			return FFTHelper.FFTValue(xreal, new double[xreal.Length], false);
		}

		/// <summary>
		/// 获取FFT变换后的显示图形，需要指定图形的相关参数
		/// </summary>
		/// <param name="xreal">实数部分的值</param>
		/// <param name="width">图形的宽度</param>
		/// <param name="heigh">图形的高度</param>
		/// <param name="lineColor">线条颜色</param>
		/// <param name="isSqrtDouble">是否开两次根，显示的噪点信息会更新明显</param>
		/// <returns>等待呈现的图形</returns>
		/// <remarks>
		/// <note type="warning">.net standrard2.0 下不支持。</note>
		/// </remarks>
		// Token: 0x06002159 RID: 8537 RVA: 0x000A1F8C File Offset: 0x000A018C
		public static Bitmap GetFFTImage(double[] xreal, int width, int heigh, Color lineColor, bool isSqrtDouble = false)
		{
			double[] ximag = new double[xreal.Length];
			double[] array = FFTHelper.FFTValue(xreal, ximag, isSqrtDouble);
			Bitmap bitmap = new Bitmap(width, heigh);
			Graphics graphics = Graphics.FromImage(bitmap);
			graphics.SmoothingMode = SmoothingMode.HighQuality;
			graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
			graphics.Clear(Color.White);
			Pen pen = new Pen(Color.DimGray, 1f);
			Pen pen2 = new Pen(Color.LightGray, 1f);
			Pen pen3 = new Pen(lineColor, 1f);
			pen2.DashPattern = new float[]
			{
				5f,
				5f
			};
			pen2.DashStyle = DashStyle.Custom;
			Font defaultFont = SystemFonts.DefaultFont;
			StringFormat stringFormat = new StringFormat();
			stringFormat.Alignment = StringAlignment.Far;
			stringFormat.LineAlignment = StringAlignment.Center;
			StringFormat stringFormat2 = new StringFormat();
			stringFormat2.LineAlignment = StringAlignment.Center;
			stringFormat2.Alignment = StringAlignment.Center;
			int num = 20;
			int num2 = 49;
			int num3 = 49;
			int num4 = 30;
			int num5 = 9;
			float num6 = (float)(heigh - num - num4);
			float num7 = (float)(width - num2 - num3);
			bool flag = array.Length > 1;
			if (flag)
			{
				double num8 = Enumerable.Max(array);
				double num9 = Enumerable.Min(array);
				num8 = ((num8 - num9 > 1.0) ? num8 : (num9 + 1.0));
				double num10 = num8 - num9;
				List<float> list = new List<float>();
				bool flag2 = array.Length >= 2;
				if (flag2)
				{
					bool flag3 = array[0] > array[1];
					if (flag3)
					{
						list.Add(0f);
					}
					for (int i = 1; i < array.Length - 2; i++)
					{
						bool flag4 = array[i - 1] < array[i] && array[i] > array[i + 1];
						if (flag4)
						{
							list.Add((float)i);
						}
					}
					bool flag5 = array[array.Length - 1] > array[array.Length - 2];
					if (flag5)
					{
						list.Add((float)(array.Length - 1));
					}
				}
				for (int j = 0; j < num5; j++)
				{
					RectangleF layoutRectangle = new RectangleF(-10f, (float)j / (float)(num5 - 1) * num6, (float)num2 + 8f, 20f);
					graphics.DrawString(((double)(num5 - 1 - j) * num10 / (double)(num5 - 1) + num9).ToString("F1"), defaultFont, Brushes.Black, layoutRectangle, stringFormat);
					graphics.DrawLine(pen2, (float)(num2 - 3), num6 * (float)j / (float)(num5 - 1) + (float)num, (float)(width - num3), num6 * (float)j / (float)(num5 - 1) + (float)num);
				}
				float num11 = num7 / (float)array.Length;
				for (int k = 0; k < list.Count; k++)
				{
					bool flag6 = array[(int)list[k]] * 200.0 / num8 > 1.0;
					if (flag6)
					{
						graphics.DrawLine(pen2, list[k] * num11 + (float)num2 + 1f, (float)num, list[k] * num11 + (float)num2 + 1f, (float)(heigh - num4));
						RectangleF layoutRectangle2 = new RectangleF(list[k] * num11 + (float)num2 + 1f - 40f, (float)(heigh - num4 + 1), 80f, 20f);
						graphics.DrawString(list[k].ToString(), defaultFont, Brushes.DeepPink, layoutRectangle2, stringFormat2);
					}
				}
				for (int l = 0; l < array.Length; l++)
				{
					PointF pt = default(PointF);
					pt.X = (float)l * num11 + (float)num2 + 1f;
					pt.Y = (float)((double)num6 - (array[l] - num9) * (double)num6 / num10 + (double)num);
					PointF pt2 = default(PointF);
					pt2.X = (float)l * num11 + (float)num2 + 1f;
					pt2.Y = (float)((double)num6 - (num9 - num9) * (double)num6 / num10 + (double)num);
					graphics.DrawLine(Pens.Tomato, pt, pt2);
				}
			}
			else
			{
				double num12 = 100.0;
				double num13 = 0.0;
				double num14 = num12 - num13;
				for (int m = 0; m < num5; m++)
				{
					RectangleF layoutRectangle3 = new RectangleF(-10f, (float)m / (float)(num5 - 1) * num6, (float)num2 + 8f, 20f);
					graphics.DrawString(((double)(num5 - 1 - m) * num14 / (double)(num5 - 1) + num13).ToString("F1"), defaultFont, Brushes.Black, layoutRectangle3, stringFormat);
					graphics.DrawLine(pen2, (float)(num2 - 3), num6 * (float)m / (float)(num5 - 1) + (float)num, (float)(width - num3), num6 * (float)m / (float)(num5 - 1) + (float)num);
				}
			}
			pen2.Dispose();
			pen.Dispose();
			pen3.Dispose();
			defaultFont.Dispose();
			stringFormat.Dispose();
			stringFormat2.Dispose();
			graphics.Dispose();
			return bitmap;
		}

		/// <summary>
		/// 快速傅立叶变换
		/// </summary>
		/// <param name="xreal">实数部分，数组长度最好为2的n次方</param>
		/// <param name="ximag">虚数部分，数组长度最好为2的n次方</param>
		/// <param name="isSqrtDouble">是否开两次根，显示的噪点信息会更新明显</param>
		/// <returns>变换后的数组值</returns>
		// Token: 0x0600215A RID: 8538 RVA: 0x000A24D8 File Offset: 0x000A06D8
		public static double[] FFTValue(double[] xreal, double[] ximag, bool isSqrtDouble = false)
		{
			int i;
			for (i = 2; i <= xreal.Length; i *= 2)
			{
			}
			i /= 2;
			double[] array = new double[i / 2];
			double[] array2 = new double[i / 2];
			FFTHelper.bitrp(xreal, ximag, i);
			double num = -6.283185307179586 / (double)i;
			double num2 = Math.Cos(num);
			double num3 = Math.Sin(num);
			array[0] = 1.0;
			array2[0] = 0.0;
			for (int j = 1; j < i / 2; j++)
			{
				array[j] = array[j - 1] * num2 - array2[j - 1] * num3;
				array2[j] = array[j - 1] * num3 + array2[j - 1] * num2;
			}
			for (int k = 2; k <= i; k *= 2)
			{
				for (int l = 0; l < i; l += k)
				{
					for (int j = 0; j < k / 2; j++)
					{
						int num4 = l + j;
						int num5 = num4 + k / 2;
						int num6 = i * j / k;
						num2 = array[num6] * xreal[num5] - array2[num6] * ximag[num5];
						num3 = array[num6] * ximag[num5] + array2[num6] * xreal[num5];
						double num7 = xreal[num4];
						double num8 = ximag[num4];
						xreal[num4] = num7 + num2;
						ximag[num4] = num8 + num3;
						xreal[num5] = num7 - num2;
						ximag[num5] = num8 - num3;
					}
				}
			}
			double[] array3 = new double[i];
			for (int m = 0; m < array3.Length; m++)
			{
				array3[m] = Math.Sqrt(Math.Pow(xreal[m], 2.0) + Math.Pow(ximag[m], 2.0));
				if (isSqrtDouble)
				{
					array3[m] = Math.Sqrt(array3[m]);
				}
			}
			return array3;
		}

		/// <summary>
		/// 快速傅立叶变换
		/// </summary>
		/// <param name="xreal">实数部分，数组长度最好为2的n次方</param>
		/// <param name="ximag">虚数部分，数组长度最好为2的n次方</param>
		/// <returns>变换后的数组值</returns>
		// Token: 0x0600215B RID: 8539 RVA: 0x000A26DC File Offset: 0x000A08DC
		public static int FFT(double[] xreal, double[] ximag)
		{
			return FFTHelper.FFTValue(xreal, ximag, false).Length;
		}

		/// <summary>
		/// 快速傅立叶变换
		/// </summary>
		/// <param name="xreal">实数部分，数组长度最好为2的n次方</param>
		/// <param name="ximag">虚数部分，数组长度最好为2的n次方</param>
		/// <returns>变换后的数组值</returns>
		// Token: 0x0600215C RID: 8540 RVA: 0x000A26F8 File Offset: 0x000A08F8
		public static int FFT(float[] xreal, float[] ximag)
		{
			return FFTHelper.FFT(Enumerable.ToArray<double>(Enumerable.Select<float, double>(xreal, (float m) => (double)m)), Enumerable.ToArray<double>(Enumerable.Select<float, double>(ximag, (float m) => (double)m)));
		}

		/// <summary>
		/// 快速傅立叶变换的逆变换
		/// </summary>
		/// <param name="xreal">实数部分，数组长度最好为2的n次方</param>
		/// <param name="ximag">虚数部分，数组长度最好为2的n次方</param>
		/// <returns>2的多少次方</returns>
		// Token: 0x0600215D RID: 8541 RVA: 0x000A2764 File Offset: 0x000A0964
		public static int IFFT(float[] xreal, float[] ximag)
		{
			return FFTHelper.IFFT(Enumerable.ToArray<double>(Enumerable.Select<float, double>(xreal, (float m) => (double)m)), Enumerable.ToArray<double>(Enumerable.Select<float, double>(ximag, (float m) => (double)m)));
		}

		/// <summary>
		/// 快速傅立叶变换的逆变换
		/// </summary>
		/// <param name="xreal">实数部分，数组长度最好为2的n次方</param>
		/// <param name="ximag">虚数部分，数组长度最好为2的n次方</param>
		/// <returns>2的多少次方</returns>
		// Token: 0x0600215E RID: 8542 RVA: 0x000A27D0 File Offset: 0x000A09D0
		public static int IFFT(double[] xreal, double[] ximag)
		{
			int i;
			for (i = 2; i <= xreal.Length; i *= 2)
			{
			}
			i /= 2;
			double[] array = new double[i / 2];
			double[] array2 = new double[i / 2];
			FFTHelper.bitrp(xreal, ximag, i);
			double num = 6.283185307179586 / (double)i;
			double num2 = Math.Cos(num);
			double num3 = Math.Sin(num);
			array[0] = 1.0;
			array2[0] = 0.0;
			for (int j = 1; j < i / 2; j++)
			{
				array[j] = array[j - 1] * num2 - array2[j - 1] * num3;
				array2[j] = array[j - 1] * num3 + array2[j - 1] * num2;
			}
			for (int k = 2; k <= i; k *= 2)
			{
				for (int l = 0; l < i; l += k)
				{
					for (int j = 0; j < k / 2; j++)
					{
						int num4 = l + j;
						int num5 = num4 + k / 2;
						int num6 = i * j / k;
						num2 = array[num6] * xreal[num5] - array2[num6] * ximag[num5];
						num3 = array[num6] * ximag[num5] + array2[num6] * xreal[num5];
						double num7 = xreal[num4];
						double num8 = ximag[num4];
						xreal[num4] = num7 + num2;
						ximag[num4] = num8 + num3;
						xreal[num5] = num7 - num2;
						ximag[num5] = num8 - num3;
					}
				}
			}
			for (int j = 0; j < i; j++)
			{
				xreal[j] /= (double)i;
				ximag[j] /= (double)i;
			}
			return i;
		}
	}
}
